'''
rgeMap - for the Random Game Generator project

By Doctus (kirikayuumura.noir@gmail.com)

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
'''
import sys
import rgeTile, rgeSystem, random
from rgeJson import loadString, loadInteger, loadObject, loadArray, loadCoordinates
from rgeSystem import mainWindow
import rgeViews

class Map(object):

    def __init__(self, textureFile, layerNumber):
        """Initializes a new map."""

        imgsize = mainWindow.glwidget.getImageSize(textureFile)
        if imgsize.width() == 0: #if failed to open file, try adding the game filepath
            textureFile = rgeViews.getGameFilepath() + textureFile
            imgsize = mainWindow.glwidget.getImageSize(textureFile)
        self.layerNumber = layerNumber
        self.mapname = textureFile
        self.mapsize = (1,1)
        self.yHeight = 1
        self.xWidth = 1
        self.tileset = textureFile
        self.tilesize = (imgsize.width(),imgsize.height())
        self.imageHeight = imgsize.height()
        self.imageWidth = imgsize.width()

        self.tileindexes = [0 for i in xrange(self.mapsize[0] * self.mapsize[1])]
        self.hidden = False
        self.tiles = None
        self.initted = False
        self._drawOffset = (0,0)

    @property
    def pixelSize(self):
        size = [self.mapsize[0], self.mapsize[1]]
        size[0] *= self.tilesize[0]
        size[1] *= self.tilesize[1]
        return size

    @property
    def drawOffset(self):
        return self._drawOffset


    def setDrawOffset(self, drawOffset):
        displacement = [0, 0]
        displacement[0] = drawOffset[0] - self._drawOffset[0]
        displacement[1] = drawOffset[1] - self._drawOffset[1]
        self._drawOffset = drawOffset
        #print "drawOffset:", drawOffset

        if self.tiles != None:
            for t in self.tiles:
                t.displaceDrawRect(displacement)

    def setMapSizeX(self,newX):
        self.setMapSize(newX,self.mapsize[1])

    def setMapSizeY(self,newY):
        self.setMapSize(self.mapsize[0],newY)

    def setMapSize(self,newX, newY):
        tempTileIndexes = self.tileindexes
        self.tileindexes = [0 for i in xrange(newX * newY)]
        for x in range(newX):
            for y in range(newY):
                if x < self.mapsize[0] and y < self.mapsize[1]:
                    self.tileindexes[x +(newX * y)] = tempTileIndexes[x + (self.mapsize[0] * y)]
        self.mapsize = (newX,newY)
        self._createTiles()

    def setTilesizeX(self, newX):
        self.setTilesize(newX, self.tilesize[1])

    def setTilesizeY(self, newY):
        self.setTilesize(self.tilesize[0], newY)

    def setTilesize(self, newX, newY):
        self.tilesize = [newX, newY]
        self._createTiles()

    def setMapProperties(self, mapsize, tilesize, yHeight, xWidth):
        self.yHeight = yHeight
        self.xWidth = xWidth
        self.tilesize = tilesize
        tempTileIndexes = self.tileindexes
        self.tileindexes = [0 for i in xrange(mapsize[0] * mapsize[1])]
        for x in range(mapsize[0]):
            for y in range(mapsize[1]):
                if x < self.mapsize[0] and y < self.mapsize[1]: #old mapsizes!
                    self.tileindexes[x +(mapsize[0] * y)] = tempTileIndexes[x + (self.mapsize[0] * y)]
        self.mapsize = mapsize
        self._createTiles()

    def hide(self, hidden=True):
        """Hide or show all tiles."""
        if hidden == self.hidden:
            return
        self.hidden = hidden
        if hidden:
            self._hideTiles()
        else:
            self._showTiles()

    def show(self):
        return self.hide(False)

    def _hideTiles(self):
        for tile in self.tiles:
            tile.setHidden(True)

    def _showTiles(self):
        if self.tiles == None:
            return
        for tile in self.tiles:
            tile.setHidden(False)

    def _deleteTiles(self):
        mainWindow.glwidget.deleteImages(self.tiles)
        self.tiles = None

    def _createTiles(self):
        """Show all the tiles of this map."""
        src = self.tileset
        imgsize = [self.xWidth * self.tilesize[0], self.yHeight * self.tilesize[1]]
        yOffset = self.imageHeight - self.yHeight * self.tilesize[1]

        if self.tiles is not None:
            mainWindow.glwidget.deleteImages(self.tiles)
            #print "deleted tiles"

        self.tiles = [None]*self.mapsize[0]*self.mapsize[1]
        mainWindow.glwidget.reserveVBOSize(self.mapsize[0] * self.mapsize[1])

        for y in xrange(0, self.mapsize[1]):
            for x in xrange(0, self.mapsize[0]):
                texx = self.tileindexes[x+self.mapsize[0]*y]%(imgsize[0]/self.tilesize[0])*self.tilesize[0]
                texy = (self.yHeight - 1 - int((self.tileindexes[x+self.mapsize[0]*y]*self.tilesize[0])/imgsize[0]))*self.tilesize[1] + yOffset
                textureRect = (texx, texy, self.tilesize[0], self.tilesize[1])
                drawRect = (x * self.tilesize[0] + self.drawOffset[0] * x, y * self.tilesize[1] + self.drawOffset[1] * y, self.tilesize[0], self.tilesize[1])
                temptile = mainWindow.glwidget.createImage(src, self.layerNumber, textureRect, drawRect, self.hidden)
                self.tiles[x+y*self.mapsize[0]] = temptile

        #print "created tiles"

    def getTile(self, tile):
        """Change the specified tile."""
        x, y = tile
        assert(0 <= x <= self.mapsize[0])
        assert(0 <= y <= self.mapsize[1])
        t = x + self.mapsize[0] * y
        return self.tileindexes[int(t)]

    def setTile(self, tile, index):
        """Change the specified tile."""
        x, y = tile
        assert(0 <= x <= self.mapsize[0])
        assert(0 <= y <= self.mapsize[1])
        t = x + self.mapsize[0] * y
        self.tileindexes[t] = index
        yOffset = self.imageHeight - self.yHeight * self.tilesize[1]

        x = index%(self.xWidth)*self.tilesize[0]
        y = (self.yHeight - 1 - int(index / self.xWidth))*self.tilesize[1] + yOffset
        self.tiles[t].setTextureRect((x, y, self.tilesize[0], self.tilesize[1]))

    def tilePosExists(self, tilepos):
        x, y = tilepos
        return ((0 <= x < self.mapsize[0]) and (0 <= y < self.mapsize[1]))

    def _setIndexes(self, indexes):
        if len(indexes) != len(self.tileindexes):
            return
        self.tileindexes[:] = indexes[:]

    @staticmethod
    def load(obj, dumpmode=False):
        """Deserialize a new map from a dictionary."""
        map = Map(
            loadString('Map.mapname', obj.get('mapname')),
            loadString('Map.authorname', obj.get('authorname')),
            loadCoordinates('Map.mapsize', obj.get('mapsize'), length=2, min=1, max=65535),
            loadString('Map.tileset', obj.get('tileset')),
            loadCoordinates('Map.tilesize', obj.get('tilesize'), length=2, min=1, max=65535),
            loadCoordinates('Map.drawoffset', obj.get('drawoffset'), length=2))

        # HACK: Looks like coordinates; saves work.
        tiles = loadCoordinates('Map.tiles', obj.get('tiles'), length=len(map.tileindexes), min=0, max=65535)
        map._setIndexes(tiles)
        map._createTiles()
        return map

    def __unicode__(self):
        return "{0} {1}".format(self.mapname, self.ID)

    def __str__(self):
        return self.__unicode__()
